package com.xinghanlaser.applet.base.auth.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinghanlaser.applet.base.auth.entity.ResourceDO;
import com.xinghanlaser.applet.base.auth.entity.RoleDO;
import com.xinghanlaser.applet.base.auth.entity.UserDO;
import com.xinghanlaser.applet.base.auth.entity.UserRoleDO;
import com.xinghanlaser.applet.base.auth.mapper.UserMapper;
import com.xinghanlaser.applet.base.auth.query.UserQuery;
import com.xinghanlaser.applet.base.auth.service.IRoleService;
import com.xinghanlaser.applet.base.auth.service.IUserRoleService;
import com.xinghanlaser.applet.base.auth.service.IUserService;

import com.xinghanlaser.applet.base.auth.vo.UserDataVO;
import com.xinghanlaser.applet.base.auth.vo.UserDetailVO;
import com.xinghanlaser.applet.base.auth.vo.UserPostVO;
import com.xinghanlaser.applet.base.auth.vo.UserPutVO;
import com.xinghanlaser.applet.base.common.entity.ResponseEntity;
import com.xinghanlaser.applet.base.common.exception.ServiceException;
import com.xinghanlaser.applet.base.common.utils.QueryUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xinghanlaser.applet.base.auth.constant.AdminConstant.*;
import static com.xinghanlaser.applet.base.auth.enums.ResourceTypeEnum.MENU;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author dym
 * @since 2019-11-19
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements IUserService {
    @Resource
    private UserMapper userMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private IRoleService roleService;

    @Resource
    private IUserRoleService userRoleService;

    @Override
    public UserDetailVO queryUserDetail(UserDO user) {
        return Optional.ofNullable(userMapper.selectUserDetail(user))
                .map(item -> {
                    UserDetailVO vo = BeanUtil.copyProperties(item, UserDetailVO.class, "resources", "roles");

                    // 处理角色
                    Set<RoleDO> roles = item.getRoles();
                    vo.setRoles(roles);

                    // 处理资源
                    Set<ResourceDO> resources = item.getResources();
                    Set<ResourceDO> menus = new HashSet<>();
                    Set<ResourceDO> buttonAndInterface = new HashSet<>();
                    resources.forEach(resource -> {
                        if(MENU.getType().equals(resource.getResourceType())) menus.add(resource);
                        else buttonAndInterface.add(resource);
                    });
                    vo.setMenus(menus);
                    vo.setResources(buttonAndInterface);

                    // 处理超级管理员
                    vo.setIsSuperAdmin(isSuperAdmin(item.getRoles()));

                    return vo;
                })
                .orElse(null);

    }

    @Override
    public ResponseEntity<ResponseEntity.PageResult<UserDataVO>> pageByCondition(UserQuery query) {
        final String userName = query.getUserName();
        final String nickName = query.getNickName();

        ResponseEntity.PageResult<UserDataVO> result = QueryUtil.query(
                query,
                () -> this.list(Wrappers.lambdaQuery(new UserDO())
                        .eq(StrUtil.isNotBlank(userName), UserDO::getUserName, userName)
                        .likeRight(StrUtil.isNotBlank(nickName), UserDO::getNickName, nickName)
                ),

                doList -> doList.stream()
                        .map(item -> BeanUtil.copyProperties(item, UserDataVO.class))
                        .collect(Collectors.toList())
        );

        return ResponseEntity.okPage(result);
    }

    @Override
    @DSTransactional
    public ResponseEntity<Void> addUser(UserPostVO postVO) {
        // 校验用户名是否重复
        validatedUserName(postVO.getUserName());

        // 保存用户数据
        final String password = postVO.getPassword();
        UserDO entity = BeanUtil.copyProperties(postVO, UserDO.class, "password");
        entity.setPassword(StrUtil.isBlank(password) ? passwordEncoder.encode(DEFAULT_USER_PASSWORD) : passwordEncoder.encode(password));

        this.save(entity);

        // 处理用户绑定角色
        final Set<Long> roleIds = postVO.getRoleIds();
        final Long userId = entity.getId();
        if(CollectionUtil.isEmpty(roleIds)) return ResponseEntity.okMsg("新增用户成功");

        Optional.of(
            roleService.getExistRoleList(roleIds)
                .stream()
                .map(roleId -> UserRoleDO.builder()
                        .userId(userId)
                        .roleId(roleId)
                        .build()
                )
                .collect(Collectors.toSet())
        )
        .filter(CollectionUtil::isNotEmpty)
        .ifPresent(userRoleService::saveBatch);

        return ResponseEntity.okMsg("新增用户成功");
    }

    @Override
    @DSTransactional
    public ResponseEntity<Void> modUser(UserPutVO putVO) {
        final Long userId = putVO.getId();

        // 校验用户ID是否存在
        validatedUserId(userId);

        // 更新用户数据
        final String password = putVO.getPassword();
        UserDO entity = BeanUtil.copyProperties(putVO, UserDO.class, "password");
        entity.setPassword(StrUtil.isBlank(password) ? passwordEncoder.encode(DEFAULT_USER_PASSWORD) : passwordEncoder.encode(password));
        this.updateById(entity);

        // 处理用户绑定角色
        final Set<Long> roleIds = putVO.getRoleIds();
        if(CollectionUtil.isEmpty(roleIds)){
            userRoleService.remove(Wrappers.lambdaQuery(new UserRoleDO()).eq(UserRoleDO::getUserId, userId));
            return ResponseEntity.okMsg("修改用户信息成功");
        }

        // 删除原有绑定关系
        userRoleService.remove(Wrappers.lambdaQuery(new UserRoleDO())
                .eq(UserRoleDO::getUserId, userId)
        );

        // 插入新的关系
        Optional.of(
                        roleService.getExistRoleList(roleIds)
                                .stream()
                                .map(roleId -> UserRoleDO.builder()
                                        .userId(userId)
                                        .roleId(roleId)
                                        .build()
                                )
                                .collect(Collectors.toSet())
                )
                .filter(CollectionUtil::isNotEmpty)
                .ifPresent(userRoleService::saveBatch);

        return ResponseEntity.okMsg("修改用户信息成功");
    }

    @Override
    public void validatedUserId(Long id) {
        Optional.ofNullable(id)
                .map(this::getById)
                .orElseThrow(() -> new ServiceException("用户不存在"));
    }

    @Override
    public ResponseEntity<Void> delUser(Long id) {
        validatedUserId(id);

        // 将用户禁用
        updateById(new UserDO()
                .setId(id)
                .setIsEnable(UN_ENABLE)
        );

        return ResponseEntity.okMsg("删除用户成功");
    }

    private Boolean isSuperAdmin(Set<RoleDO> roles){
        if(CollectionUtil.isEmpty(roles)) return false;

        for (RoleDO role : roles) {
            if(SUPER_ADMIN_ROLE_ID.equals(role.getId())){
                return true;
            }
        }

        return false;
    }

    private void validatedUserName(String userName){
        if(StrUtil.isBlank(userName)){
            throw new ServiceException("校验用户名不能为空");
        }

        UserDO exist = this.getOne(Wrappers.lambdaQuery(new UserDO())
                .select(UserDO::getId)
                .eq(UserDO::getUserName, userName)
                .last("LIMIT 1")
        );

        if(exist != null){
            throw new ServiceException("用户名已存在");
        }
    }


}
